package com.x2.modular.system.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.x2.base.auth.context.LoginContextHolder;
import com.x2.base.auth.model.LoginUser;
import com.x2.base.consts.ConstantsContext;
import com.x2.core.constant.DefaultAvatar;
import com.x2.core.exception.enums.BizExceptionEnum;
import com.x2.core.util.DateUtils;
import com.x2.core.util.ListUtil;
import com.x2.core.util.ToolUtil;
import com.x2.kernel.model.exception.ServiceException;
import com.x2.kernel.model.exception.enums.CoreExceptionEnum;
import com.x2.kernel.model.response.ResponseData;
import com.x2.modular.system.entity.FileInfo;
import com.x2.modular.system.entity.User;
import com.x2.modular.system.mapper.FileInfoMapper;
import com.x2.modular.system.model.UploadResult;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 文件信息表服务实现类
 *
 * @author stylefeng
 * @since 2018-12-07
 */
@Service
@Slf4j
public class FileInfoService extends ServiceImpl<FileInfoMapper, FileInfo> {
    // 签名图片路径标识
    public final static String SIGN = "sign";

    @Autowired
    private UserService userService;

    /**
     * 根据类型标识获取根目录
     *
     * @param type: 类型标识
     * @return 根目录
     */
    public String getRootPath(String type) {
        if (ToolUtil.isEmpty(type)) {
            return ConstantsContext.getFileUploadPath();
        } else if (type.equals(SIGN)) {
            return ConstantsContext.getSignImagePath();
        } else {
            return ConstantsContext.getFileUploadPath();
        }
    }

    /**
     * 更新头像
     *
     * @author fengshuonan
     * @Date 2018/11/10 4:10 PM
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateAvatar(String fileId) {
        LoginUser currentUser = LoginContextHolder.getContext().getUser();
        if (currentUser == null) {
            throw new ServiceException(CoreExceptionEnum.NO_CURRENT_USER);
        }
        User user = userService.getById(currentUser.getId());
        //更新用户的头像
        user.setAvatar(fileId);
        userService.updateById(user);
    }

    /**
     * 预览当前用户头像     *
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:04
     */
    public byte[] previewAvatar() {
        LoginUser currentUser = LoginContextHolder.getContext().getUser();
        if (currentUser == null) {
            throw new ServiceException(CoreExceptionEnum.NO_CURRENT_USER);
        }
        //获取当前用户的头像id
        User user = userService.getById(currentUser.getId());
        String avatar = user.getAvatar();
        //如果头像id为空就返回默认的
        if (ToolUtil.isEmpty(avatar)) {
            return Base64.decode(DefaultAvatar.BASE_64_AVATAR);
        } else {
            //文件id不为空就查询文件记录
            FileInfo fileInfo = this.getById(avatar);
            if (fileInfo == null) {
                return Base64.decode(DefaultAvatar.BASE_64_AVATAR);
            } else {
                try {
                    String filePath = getRootPath(null) + File.separator + fileInfo.getFilePath();
                    return IoUtil.readBytes(new FileInputStream(filePath));
                } catch (FileNotFoundException e) {
                    log.error("头像未找到！", e);
                    return Base64.decode(DefaultAvatar.BASE_64_AVATAR);
                }
            }
        }
    }

    public byte[] previewImage(String fileId) {
        FileInfo fileInfo = this.getById(fileId);
        if (fileInfo == null) {
            return Base64.decode(DefaultAvatar.BASE_64_AVATAR);
        } else {
            try {
                String filePath = getRootPath(null) + File.separator + fileInfo.getFilePath();
                return IoUtil.readBytes(new FileInputStream(filePath));
            } catch (FileNotFoundException e) {
                log.error("头像未找到！", e);
                return Base64.decode(DefaultAvatar.BASE_64_AVATAR);
            }
        }
    }

    /**
     * 上传文件（默认上传路径）
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:18
     */
    public UploadResult uploadFile(MultipartFile file) {
        String fileSavePath = getRootPath(null);
        fileSavePath = fileSavePath.trim();
        String logicPath = DateUtils.getDate("yyyy/MM/dd");
        while (fileSavePath.endsWith("/") || fileSavePath.endsWith("\\")) {
            fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
        }
        fileSavePath = fileSavePath + "/" + logicPath + "/";
        return this.uploadFile(file, fileSavePath, logicPath);
    }

    /**
     * 下载文件（默认上传路径）
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:18
     */
    public File downFile(String logicFilePath) {
        return downFile(logicFilePath, null);
    }

    /**
     * 下载文件（默认上传路径）
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:18
     */
    public File downFile(String logicFilePath, String type) {
        String fileSavePath = getRootPath(type);
        fileSavePath = fileSavePath.trim();
        String file;
        while (fileSavePath.endsWith("/") || fileSavePath.endsWith("\\")) {
            fileSavePath = fileSavePath.substring(0, fileSavePath.length() - 1);
        }
        file = fileSavePath + "/" + logicFilePath;
        return new File(file);
    }

    /**
     * 删除文件
     *
     * @param fileId：文件id
     * @return 结果
     */
    public ResponseData deleteByFileId(String fileId, String type) {
        FileInfo fileInfo = this.getById(fileId);
        if (fileInfo == null) {
            return ResponseData.error("文件不存在");
        }
        File file = new File(getRootPath(type) + File.separator + fileInfo.getFilePath());
        if (file.delete()) {
            this.baseMapper.deleteById(fileId);
            String thumbnailPath = ToolUtil.replaceStr(fileInfo.getFilePath(), ".", "-thumbnail.");
            File fileThumbnail = new File(ConstantsContext.getFileUploadPath() + File.separator + thumbnailPath);
            fileThumbnail.delete();
        }
        return ResponseData.success();
    }

    /**
     * 上传文件（指定上传路径）
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:18
     */
    private UploadResult uploadFile(MultipartFile file, String savePath, String logicPath) {
        UploadResult uploadResult = new UploadResult();
        //生成文件的唯一id
        String fileId = IdWorker.getIdStr();
        uploadResult.setFileId(fileId);
        //获取文件后缀
        String fileSuffix = ToolUtil.getFileSuffix(file.getOriginalFilename());
        uploadResult.setFileSuffix(fileSuffix);
        //获取文件原始名称
        String originalFilename = file.getOriginalFilename();
        uploadResult.setOriginalFilename(originalFilename);
        //生成文件的最终名称
        String finalName = fileId + "." + ToolUtil.getFileSuffix(originalFilename);
        String thumbnailFileName = fileId + "-thumbnail.png";
        uploadResult.setFinalName(finalName);
        uploadResult.setFileSavePath(logicPath + "/" + finalName);
        try {
            File fileSavePathFile = new File(savePath);
            if (!fileSavePathFile.exists() || !fileSavePathFile.isDirectory()) {
                fileSavePathFile.mkdirs();
            }
            File newFile = new File(savePath + finalName);
            file.transferTo(newFile);
            //保存文件信息
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileId(fileId);
            fileInfo.setFileName(originalFilename);
            fileInfo.setFileSuffix(fileSuffix);
            fileInfo.setFilePath(logicPath + "/" + finalName);
            fileInfo.setFinalName(finalName);
            //计算文件大小kb
            long kb = new BigDecimal(file.getSize()).divide(BigDecimal.valueOf(1024)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            fileInfo.setFileSizeKb(kb);
            uploadResult.setFileSize(kb);
            this.save(fileInfo);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件错误！", e);
            throw new ServiceException(BizExceptionEnum.UPLOAD_ERROR);
        }
        return uploadResult;
    }

    /**
     * 下载
     *
     * @param ids: 文件id
     * @return 结果
     */
    public List<UploadResult> downlaodFileByIds(String ids) {
        if (ids == null || ids.trim().length() <= 0) {
            return new ArrayList<>();
        }
        QueryWrapper<FileInfo> fileWrapper = new QueryWrapper<>();
        fileWrapper.in("file_id", ListUtil.toLongArr(ids));
        List<FileInfo> fileList = this.list(fileWrapper);
        List<UploadResult> resList = new ArrayList<>();
        if (fileList != null) {
            for (FileInfo info : fileList) {
                UploadResult rs = new UploadResult();
                rs.setOriginalFilename(info.getFileName());
                rs.setFileSavePath(info.getFilePath());
                rs.setFileId(info.getFileId());
                resList.add(rs);
            }
            return resList;
        }
        return new ArrayList<>();
    }

    public String getContextPath() {
        String dateStr = DateUtil.format(new Date(), "yyyy/MM/dd");
        return dateStr;
    }

    public String getAbsolutePath() {
        return (ConstantsContext.getFileUploadPath() + File.separator + getContextPath()) + File.separator;
    }

    /**
     * 根据base64编码上传图片
     *
     * @param base64：图片编码
     * @param type:       跟目录路径标识
     * @return 上传结果
     */
    public ResponseData uploadBase64(String base64, String type) {
        String fileSuffix = "png";
        if (base64.indexOf("data:image") > -1) {
            String[] array = ToolUtil.splitStr(base64, ';');
            fileSuffix = ToolUtil.replaceStr(array[0], "data:image/", "");
            base64 = base64.replaceFirst("data:image/" + fileSuffix + ";base64,", "");
        }
        UploadResult uploadResult = new UploadResult();
        //生成文件的唯一id
        String fileId = IdWorker.getIdStr();
        uploadResult.setFileId(fileId);
        uploadResult.setFileSuffix(fileSuffix);
        uploadResult.setOriginalFilename(fileId);
        //生成文件的最终名称
        String finalName = fileId + "." + fileSuffix;
        String thumbnailFileName = fileId + "-thumbnail.png";
        uploadResult.setFinalName(finalName);
        String savePath = getRootPath(type);
        String logicPath = DateUtils.getDate("yyyy/MM/dd");
        while (savePath.endsWith("/") || savePath.endsWith("\\")) {
            savePath = savePath.substring(0, savePath.length() - 1);
        }
        savePath = savePath + "/" + logicPath + "/";
        uploadResult.setFileSavePath(logicPath + "/" + finalName);
        long fileSize = 0L;
        try {
            File fileSavePathFile = new File(savePath);
            if (!fileSavePathFile.exists() || !fileSavePathFile.isDirectory()) {
                fileSavePathFile.mkdirs();
            }
            File newFile = new File(savePath + finalName);
            byte[] bs = Base64.decode(base64);
            fileSize = bs.length;
            BufferedOutputStream bos = null;
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(newFile);
                bos = new BufferedOutputStream(fos);
                bos.write(bs);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bos != null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            FileInfo fileInfo = new FileInfo();
            //保存文件信息
            fileInfo.setFileId(fileId);
            fileInfo.setFileName(fileId);
            fileInfo.setFileSuffix(fileSuffix);
            fileInfo.setFilePath(logicPath + "/" + finalName);
            fileInfo.setFinalName(finalName);
            //计算文件大小kb
            long kb = new BigDecimal(fileSize).divide(BigDecimal.valueOf(1024)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            fileInfo.setFileSizeKb(kb);
            uploadResult.setFileSize(kb);
            this.save(fileInfo);
        } catch (Exception e) {
            log.error("上传文件错误！", e);
            return ResponseData.error("图片上传失败");
        }
        return ResponseData.success(uploadResult);
    }

    /**
     * 预览
     *
     * @param fileId:        文件id
     * @param type：文件存储根目录类型
     * @param response
     */
    public void preview(String fileId, String type, HttpServletResponse response) {
        FileInfo attach = this.getById(fileId);
        if (attach == null) {
            buildResponse(response, "文件不存在");
            return;
        }
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        response.setHeader("Content-Type", "image/jpeg");
        File file = downFile(attach.getFilePath(), type);
        if (file == null || !file.exists()) {
            buildResponse(response, "文件不存在");
            return;
        }
        byte[] bytes = new byte[1024];
        int read;
        try {
            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());
            while ((read = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, read);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 下载文件
     *
     * @param fileId：文件id
     * @param type：根目录类型标识
     * @param response:    响应
     * @throws IOException 异常
     */
    public void downloadFile(String fileId, String type, HttpServletResponse response) throws IOException {
        downloadFile(this.getById(fileId), type, response);
    }

    /**
     * 下载文件
     *
     * @param attach：文件对象
     * @param type：根目录类型标识
     * @param response:    响应
     * @throws IOException 异常
     */
    public void downloadFile(FileInfo attach, String type, HttpServletResponse response) throws IOException {
        if (attach == null) {
            buildResponse(response, "文件不存在");
            return;
        }
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName=\"" + new String(attach.getFileName().getBytes(), "ISO8859-1") + "\"");
        File file = downFile(attach.getFilePath(), type);
        if (file == null || !file.exists()) {
            buildResponse(response, "文件不存在");
            return;
        }
        InputStream is = null;
        ServletOutputStream out = null;
        try {
            is = new FileInputStream(file);
            out = response.getOutputStream();
            out.write(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            ToolUtil.closeQuietly(out);
            ToolUtil.closeQuietly(is);
        }
    }

    /**
     * 错误返回结果
     *
     * @param response: 响应
     * @param message:  消息
     * @throws IOException 异常
     */
    public void buildResponse(HttpServletResponse response, String message) {
        try {
            Map<String, String> resMap = new HashMap<>(2);
            resMap.put("code", "405");
            resMap.put("message", message);
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(JSONUtil.toJsonStr(resMap));
            writer.flush();
            writer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 上传文件（默认上传路径）
     *
     * @author fengshuonan
     * @Date 2019-05-04 17:18
     */
    public UploadResult uploadFile(File file) throws ServiceException {
        String savePath = getRootPath(null);
        savePath = savePath.trim();
        String logicPath = DateUtils.getDate("yyyy/MM/dd");
        while (savePath.endsWith("/") || savePath.endsWith("\\")) {
            savePath = savePath.substring(0, savePath.length() - 1);
        }
        savePath = savePath + "/" + logicPath + "/";
        UploadResult uploadResult = new UploadResult();
        //生成文件的唯一id
        String fileId = IdWorker.getIdStr();
        uploadResult.setFileId(fileId);
        //获取文件后缀
        String fileSuffix = ToolUtil.getFileSuffix(file.getName());
        uploadResult.setFileSuffix(fileSuffix);
        //获取文件原始名称
        String originalFilename = file.getName();
        uploadResult.setOriginalFilename(originalFilename);
        //生成文件的最终名称
        String finalName = fileId + "." + ToolUtil.getFileSuffix(originalFilename);
        String thumbnailFileName = fileId + "-thumbnail.png";
        uploadResult.setFinalName(finalName);
        uploadResult.setFileSavePath(logicPath + "/" + finalName);
        try {
            File fileSavePathFile = new File(savePath);
            if (!fileSavePathFile.exists() || !fileSavePathFile.isDirectory()) {
                fileSavePathFile.mkdirs();
            }
            File newFile = new File(savePath + finalName);
            OutputStream os = new FileOutputStream(newFile);
            InputStream is = new FileInputStream(file);
            byte[] bts = new byte[1024];
            while (is.read(bts) != -1) {
                os.write(bts);
            }
            os.flush();
            os.close();
            is.close();
            //保存文件信息
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileId(fileId);
            fileInfo.setFileName(originalFilename);
            fileInfo.setFileSuffix(fileSuffix);
            fileInfo.setFilePath(logicPath + "/" + finalName);
            fileInfo.setFinalName(finalName);
            //计算文件大小kb
            long kb = new BigDecimal(file.length()).divide(BigDecimal.valueOf(1024)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            fileInfo.setFileSizeKb(kb);
            uploadResult.setFileSize(kb);
            this.save(fileInfo);
        } catch (Exception e) {
            log.error("上传文件错误！", e);
            throw new ServiceException(BizExceptionEnum.UPLOAD_ERROR);
        }
        return uploadResult;
    }
}
